<%@ page language="java" pageEncoding="UTF-8" isErrorPage="false" %>
<jsp:directive.page import="java.security.MessageDigest"/>
<%!
	// 密钥
	private static final String KEY = ":cookie@wanghua.com";

	// MD5 加密算法
	public final static String calcMD5(String ss) {
		String s = ss == null ? "" : ss;

		char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};  //字典
		try {
			byte[] strTemp = s.getBytes();
			MessageDigest mdTemp = MessageDigest.getInstance("MD5");  //获取MD5
			mdTemp.update(strTemp);   //更新数据
			byte[] md = mdTemp.digest();  //加密
			int j = md.length;   //加密后的长度
			char str[] = new char[j * 2];  //新字符串数组
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			return null;
		}
	}
%>
<%
	request.setCharacterEncoding("UTF-8");
	response.setCharacterEncoding("UTF-8");
	
	String action = request.getParameter("action");

	if("login".equals(action)){
		/*
		* 用户若是在家上网，登录后就可以记住他的登录信息，下次访问时就不要再登录了。
		* 保存登录信息有多种方案。最直接的就是把用户名和加密的密码都保持到cookie中，如果不希望保存密码，还可以把登录的时间戳保存到cookie与数据库中，
		* 到时候验证帐号名和时间戳就可以了。这几种方案都需要查询数据库。本例将采用另一种方案：只在登录时查询一次数据库。实现方式是用户登录后，将
		* 帐号与ssid(帐号+密钥进行MD5算法加密后的值)存入cookie，下次只要在后台验证cookie中的ssid是否等于帐号+密钥进行MD5算法加密后的值。
		*
		* 实际项目中，第一次登录应该先认证，用帐号和密码去数据库查一下。认证成功后，再在cookie生成ssid发往客户端，下次就可以自动登录了。
		* 也就是说，这里应该先判断 cookie 中 ssid 是否存在，不存在就等查一次数据库来认证。
		* 注：跨域名cookie现在被广泛使用，如：google、baidu、sina等，这种大型公司都有好多服务器提供不同服务，使用跨域名是有好处的。
		*
		* 注：这种方式我认为是有安全漏洞的。一旦黑客知道了cookie中的ssid和account，那么他就可以简单做个系统，模拟请求，携带这两个信息。
		* 但又由于cookie domain的限制，他的系统的域名与我们的系统的域名是不同的，所以上面的担心似乎没必要。
		*
		* 注：要使登录长期有效，使用cookie比session好，设置maxAge就可以了。session利润上也能实现，只要设置超时时间，但session依赖名为jssessionid的cookie。
		* 而此 cookie 的 maxAge 默认为 -1,只要关闭浏览器该session就会失效。而且如果设置session的超时时间过长，服务器容易导致内存溢出。
		* */

 		String account = request.getParameter("account");
		String password = request.getParameter("password");
		int timeout = new Integer(request.getParameter("timeout"));

		// 把帐号连同密钥使用MD5后加密后保存
		String ssid = calcMD5(account + KEY);
				
		// 把帐号保存到Cookie中 并控制有效期
		Cookie accountCookie = new Cookie("account", account);
		accountCookie.setMaxAge(timeout);
		
		// 把加密结果保存到Cookie中 并控制有效期
		Cookie ssidCookie = new Cookie("ssid", ssid);
		ssidCookie.setMaxAge(timeout);
		
		response.addCookie(accountCookie);
		response.addCookie(ssidCookie);
		
		// 重新请求本页面
		response.sendRedirect(request.getRequestURI() + "?" + System.currentTimeMillis());
		return;
	}
	else if("logout".equals(action)){

		// 删除Cookie中的帐号
		Cookie accountCookie = new Cookie("account", "");
		accountCookie.setMaxAge(0);
		
		// 删除Cookie中的加密结果
		Cookie ssidCookie = new Cookie("ssid", "");
		ssidCookie.setMaxAge(0);

		response.addCookie(accountCookie);
		response.addCookie(ssidCookie);

		// 重新请求本页面
		response.sendRedirect(request.getRequestURI() + "?" + System.currentTimeMillis());
		return;
	}
	
	boolean loggin = false;
	
	String account = null;
	String ssid = null;
	
	// 获取Cookie中的account与ssid
	if(request.getCookies() != null){
		for(Cookie cookie : request.getCookies()){
			if(cookie.getName().equals("account"))
				account = cookie.getValue();
			if(cookie.getName().equals("ssid"))
				ssid = cookie.getValue();
		}
	}
	
	if(account != null && ssid != null){
		// 如果加密规则正确, 则视为已经登录
		loggin = ssid.equals(calcMD5(account + KEY));
	}
	
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title><%= loggin ? "欢迎您回来" : "请先登录" %></title>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div align="center" style="margin:10px; ">
	<fieldset>
		<legend>当前有效的 Cookie</legend>
		<script>document.write(document.cookie);</script>
	</fieldset>
	<fieldset>
		<legend><%= loggin ? "欢迎您回来" : "请先登录" %></legend>
		<% if(loggin){ %>
			欢迎您, ${ cookie.account.value }. &nbsp;&nbsp; 
			<a href="${ pageContext.request.requestURI }?action=logout">注销</a>
		<% } else { %>
		<form action="${ pageContext.request.requestURI }?action=login" method="post">
			<table>
				<tr>
					<td>
						帐号：
					</td>
					<td>
						<input type="text" name="account" style="width:200px; ">
					</td>
				</tr>
				<tr>
					<td>
						密码：
					</td>
					<td>
						<input type="password" name="password" style="width:200px; ">
					</td>
				</tr>
				<tr>
					<td>
						有效期：
					</td>
					<td>
						<input type="radio" name="timeout" value="-1" checked> 关闭浏览器即失效 <br/>
						<input type="radio" name="timeout" value="<%= 30 * 24 * 60 * 60 %>"> 30天内有效 <br/>
						<input type="radio" name="timeout" value="<%= Integer.MAX_VALUE %>"> 永久有效 <br/>
					</td>
				</tr>
				<tr>
					<td>
					</td>
					<td>
						<input type="submit" value=" 登  录 " class="button">
					</td>
				</tr>
			</table>
		</form>
		<% } %>
	</fieldset>
</div>

</body>
</html>
